!> author: 左志华
!> date: 2022-07-16
!>
!> Project, method and configuration <br>
!> 项目及方法、配置
!> @note bad code
module sph_project_type

    use seakeeping_filesystem, only: is_exist
    use seakeeping_string, only: to_string
    use sph_kinds, only: rk
    use sph_region, only: region_t
    use sph_leap_frog, only: leap_frog_calc, time_integration_fcn
    use sph_smoothed_kernel_function, only: skf
    use sph_density_summation, only: denormalized_density_summation, density_summation_type, &
                                     normalized_density_summation, density, denormalized_density_summation
    use sph_internal_force, only: internal_force, internal_force_without_visc, viscosity
    use sph_eos, only: eos_type, p_water, p_water_morris, p_water_monaghan, c0
    use sph_external_force, only: gravity, external_force, external_force_without_gravity, r0, dd
    use sph_navier_stokes_solver, only: dt
    use sph_env, only: dim, nums

    !> Project type <br>
    !> 项目
    !> @note Bad code
    type project_t
        character(:), allocatable :: name   !! Project name <br>
                                            !! 项目名称
        character(:), allocatable :: path   !! Project path <br>
                                            !! 项目路径
                                            !! @note 输入路径: tmpin <br>
                                            !!       输出路径: tmpout
        integer :: nstep                    !! Number of steps <br>
                                            !! 时间步数
        real(rk) :: CFL                     !! CFL number <br>
                                            !! CFL数值
        logical :: adaptive_step_size       !! Adaptive step size <br>
                                            !! 自适应步长
        integer :: innps                    !! 近邻粒子搜索 (nearest neighbor particle search) <br>
                                            !! 1: 链表法
                                            !! 2: 直接搜索 (仅具有理论意义，工程上计算效率极低)
        integer :: max_number_npp           !! maximum number of particles pairs <br>
                                            !! 预设近邻粒子对最大数目
        logical :: gravity                  !! gravity on/off <br>
                                            !! 是否启用重力
        logical :: artificial_viscous       !! artificial viscosity on/off <br>
                                            !! 是否启用人工粘性
        logical :: artificial_heat          !! artificial heat on/off <br>
                                            !! 是否启用人工热能
        logical :: go_on                    !! go on or not <br>
                                            !! 是否继续运行
        integer :: go_on_step               !! go on step <br>
                                            !! 继续运行的步数
        integer :: itime_integration        !! integration method <br>
                                            !! 时间积分方案 (算法): <br>
                                            !! 1. 蛙跳积分法; <br>
                                            !! 2. 四阶龙格库塔法;
        integer(8) :: fid                   !! h5part file id <br>
                                            !! h5part文件单元号
        ! @todo 具体求解器算法选择移交到独立的类中
        procedure(time_integration_fcn), nopass, pointer :: time_integration => null()  !! 时间积分方案
    contains
        procedure :: set_methods => project_t_set_methods
    end type project_t

contains

    !> Based on the configuration file, determine the solver method of the project
    !> 根据配置文件确定工程的求解器方法及参数
    impure subroutine project_t_set_methods(self, region, hsml)
        use sph_env, only: vmin, rmin, umin
        class(project_t), intent(inout) :: self  !! 项目
        type(region_t), intent(in) :: region  !! 区域
        real(rk), intent(in) :: hsml  !! 光滑长度
        call skf%setup_kernel(hsml)
        select case (self%itime_integration)    ! 时间积分方案
        case (1)
            self%time_integration => leap_frog_calc
        end select
        if (self%adaptive_step_size) dt = self%CFL*hsml/(c0*10)
        allocate (vmin(dim, nums(1)), &
                  rmin(nums(1)), &
                  umin(nums(1)))

        select case (density_summation_type)
        case (2); density => normalized_density_summation
        case (3); density => denormalized_density_summation
        end select

        if (.not. viscosity) then
            internal_force => internal_force_without_visc
        end if

        select case (eos_type)
        case (2); p_water => p_water_monaghan
        case (3); p_water => p_water_morris
        end select

        if (.not. gravity) then
            external_force => external_force_without_gravity
        end if
        r0 = hsml*0.995_rk
        dd = (c0)**2/10

    end subroutine project_t_set_methods

end module sph_project_type
